package com.m4f.gaeweb.business.service.impl;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.m4f.gaeweb.business.service.ifc.IGenericDAOBaseService;
import com.m4f.gaeweb.persistence.dao.ifc.DAOSupport;

public abstract class GenericDAOBaseService<T> implements IGenericDAOBaseService<T> {
	protected DAOSupport DAO;
	protected Class<T> clazz;
	
	public GenericDAOBaseService(DAOSupport dao, Class<T> clazz) {
		this.DAO = dao;
		this.clazz = clazz;
	}
	
	public T create() {
		return this.DAO.createInstance(clazz);
	}
	
	public void save(T t) throws Exception {
		this.DAO.saveOrUpdate(t);
	}
	
	public void delete(T t) throws Exception {
		this.DAO.delete(t);
	}
	
	public List<T> getAll() throws Exception {
		return this.DAO.findAll(clazz);
	}
	
	public long count() {
		return this.DAO.count(clazz);
	}
	
	public T getObjectById(Long id) throws Exception {
		return this.DAO.findById(clazz, id);
	}
	
	public Collection<T> getObjectsBy(String ordering, String filterBy, String filterValue, int init, int end) {
		// TODO TESTING FOR USE IT IN TABLES!!
		if(filterBy != null && filterValue != null && !("").equals(filterBy) && !("").equals(filterValue)) {			
			String filter = filterBy + " >= " + " param " + " && " + filterBy + " < " + " hack ";
			String typeParam = "java.lang.String ";
			
			String hack =  filterValue + "\ufffd";
			try {
				Field field = clazz.getDeclaredField(filterBy);
				typeParam = field.getType().getCanonicalName();
				String param = typeParam + " param, " + typeParam + " hack ";
				Constructor constructor = field.getType().getConstructor(filterValue.getClass());
				Object value = constructor.newInstance(new Object[] {filterValue});
				Object[] values = new Object[] {value, hack};
				
				return this.DAO.findEntitiesByRange(clazz, filter, param, values, filterBy, init, end);
			} catch(Exception e) {
				e.printStackTrace();				
			}
		} 
		return this.DAO.findEntitiesByRange(clazz, ordering, init, end);
	}
	
	@Override
	public Collection<T> getObjectsByIds(List<Long> objectIds, String ordering, String filterBy, String filterValue, int init, int end) throws Exception {
		if(objectIds.size() > 0) {
			// TODO TESTING FOR USE IT IN TABLES!!
			StringBuffer filter = new StringBuffer("(");
			StringBuffer typeParam = new StringBuffer();
			ArrayList values = new ArrayList(objectIds);
			for(int i = 0; i < objectIds.size() ; i++) {
				Long appId = objectIds.get(i);
				filter.append(" id == ").append("idParam").append(i);
				typeParam.append("java.lang.Long idParam").append(i);
				if(i+1 < objectIds.size()) {
					filter.append(" || ");
					typeParam.append(",");
				} else {
					filter.append(") ");
				}
			}
				
			if(!("").equals(filterBy) && !("").equals(filterValue)) {			
				filter.append(" && ").append(filterBy).append(" == ").append(" param ");
				//typeParam.append("java.lang.String ");
			
				try {
					Field field = clazz.getDeclaredField(filterBy);
					typeParam.append(field.getType().getCanonicalName()).append(" param");
					//String param = typeParam.toString() + " param";
					Constructor constructor = field.getType().getConstructor(filterValue.getClass());
					Object value = constructor.newInstance(new Object[] {filterValue});
					values.add(value);
				} catch(Exception e) {
					e.printStackTrace();				
				}
			} 
			
			return this.DAO.findEntitiesByRange(clazz, filter.toString(), typeParam.toString(), values.toArray(), ordering, init, end);
		} else {
			return this.getObjectsBy(ordering, filterBy, filterValue, init, end);
		}
	}
}
